home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / ppplcp.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  28KB  |  1,133 lines

  1. /*
  2.  *  PPPLCP.C    -- negotiate data link options
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  *
  11.  * ATARI Version David Nash - dnash@chaos.demon.co.uk
  12.  */
  13.  
  14. /****************************************************************************
  15. *    $Id: ppplcp.c 1.4 93/07/16 11:49:20 ROOT_DOS Exp $
  16. *    29 May 92    1.2        GT    lcp_stopping (): don't shut down device.        *
  17. *    11 Aug 92    1.3        GT    Make dolcp_open () public.                        *
  18. *    14 Jul 93    1.4        GT    Fix warnings.                                    *
  19. ****************************************************************************/
  20.  
  21. #include <stdio.h>
  22. #include "global.h"
  23. #include "mbuf.h"
  24. #include "iface.h"
  25. #include "socket.h"
  26. #include "ppp.h"
  27. #include "pppfsm.h"
  28. #include "ppplcp.h"
  29. #include "ppppap.h"
  30. #include "cmdparse.h"
  31. #include "devparam.h"
  32. #include "trace.h"
  33. #include "ip.h"
  34.  
  35.  
  36. /* These defaults are defined in the PPP RFCs, and must not be changed */
  37. static struct lcp_value_s lcp_default = {
  38.     FALSE,        /* no need to negotiate defaults */
  39.  
  40.     LCP_MRU_DEFAULT,
  41.     LCP_ACCM_DEFAULT,
  42.     0,        /* no authentication */
  43.     0,        /* no encryption */
  44.     0L,        /* no magic number */
  45.     0L,        /* no reporting period */
  46. };
  47.  
  48. /* for test purposes, accept anything we understand in the NAK */
  49. static int16 lcp_negotiate = LCP_N_MRU | LCP_N_ACCM | LCP_N_AUTHENT
  50.         | LCP_N_PFC | LCP_N_ACFC | LCP_N_MAGIC;
  51.  
  52. static byte_t option_length[] = {
  53.      0,        /* unused */
  54.      4,        /* MRU */
  55.      6,        /* ACCM */
  56.      4,        /* authentication */
  57.      4,        /* encryption */
  58.      6,        /* magic number */
  59.      6,        /* monitor reporting period */
  60.      2,        /* Protocol compression */
  61.      2        /* Address/Control compression */
  62. };
  63.  
  64.  
  65. static int dolcp_local        __ARGS((int argc, char *argv[], void *p));
  66. #if    0
  67. static int dolcp_open        __ARGS((int argc, char *argv[], void *p));
  68. #endif
  69. static int dolcp_remote        __ARGS((int argc, char *argv[], void *p));
  70.  
  71. static int dolcp_accm        __ARGS((int argc, char *argv[], void *p));
  72. static int dolcp_acfc        __ARGS((int argc, char *argv[], void *p));
  73. static int dolcp_auth        __ARGS((int argc, char *argv[], void *p));
  74. static int dolcp_magic        __ARGS((int argc, char *argv[], void *p));
  75. static int dolcp_mru        __ARGS((int argc, char *argv[], void *p));
  76. static int dolcp_pfc        __ARGS((int argc, char *argv[], void *p));
  77. static int dolcp_default    __ARGS((int argc, char *argv[], void *p));
  78.  
  79. static void lcp_option __ARGS((struct mbuf **bpp,
  80.             struct lcp_value_s *value_p,
  81.             byte_t o_type,
  82.             byte_t o_length,
  83.             struct mbuf **copy_bpp ));
  84. static void lcp_makeoptions __ARGS((struct mbuf **bpp,
  85.             struct lcp_value_s *value_p,
  86.             int16 negotiating));
  87. static struct mbuf *lcp_makereq __ARGS((struct fsm_s *fsm_p));
  88.  
  89. static int lcp_check __ARGS((struct mbuf **bpp,
  90.             struct lcp_s *lcp_p,
  91.             struct lcp_side_s *side_p,
  92.             struct option_hdr *option_p,
  93.             int request));
  94.  
  95. static int lcp_request    __ARGS((struct fsm_s *fsm_p,
  96.             struct config_hdr *config,
  97.             struct mbuf *data));
  98. static int lcp_ack    __ARGS((struct fsm_s *fsm_p,
  99.             struct config_hdr *ackcnf,
  100.             struct mbuf *data));
  101. static int lcp_nak    __ARGS((struct fsm_s *fsm_p,
  102.             struct config_hdr *nakcnf,
  103.             struct mbuf *data));
  104. static int lcp_reject    __ARGS((struct fsm_s *fsm_p,
  105.             struct config_hdr *rejcnf,
  106.             struct mbuf *data));
  107.  
  108. static void lcp_reset    __ARGS((struct fsm_s *fsm_p));
  109. static void lcp_starting __ARGS((struct fsm_s *fsm_p));
  110. static void lcp_stopping __ARGS((struct fsm_s *fsm_p));
  111.  
  112. static void lcp_closing __ARGS((struct fsm_s *fsm_p));
  113. static void lcp_opening __ARGS((struct fsm_s *fsm_p));
  114.  
  115. static void lcp_free    __ARGS((struct fsm_s *fsm_p));
  116.  
  117.  
  118. static struct fsm_constant_s lcp_constants = {
  119.     "Lcp",
  120.     PPP_LCP_PROTOCOL,
  121.     0x0FFE,                /* codes 1-11 recognized */
  122.  
  123.     Lcp,
  124.     LCP_REQ_TRY,
  125.     LCP_NAK_TRY,
  126.     LCP_TERM_TRY,
  127.     LCP_TIMEOUT * 1000L,
  128.  
  129.     lcp_free,
  130.  
  131.     lcp_reset,
  132.     lcp_starting,
  133.     lcp_opening,
  134.     lcp_closing,
  135.     lcp_stopping,
  136.  
  137.     lcp_makereq,
  138.     lcp_request,
  139.     lcp_ack,
  140.     lcp_nak,
  141.     lcp_reject
  142. };
  143.  
  144.  
  145. /************************************************************************/
  146.  
  147. /* "ppp <iface> lcp" subcommands */
  148. static struct cmds Lcpcmds[] = {
  149.     { "close",    doppp_close,    0,    0,    NULLCHAR },
  150.     { "listen",    doppp_passive,    0,    0,    NULLCHAR },
  151.     { "local",    dolcp_local,    0,    0,    NULLCHAR },
  152.     { "open",        dolcp_open,    0,    0,    NULLCHAR },
  153.     { "remote",    dolcp_remote,    0,    0,    NULLCHAR },
  154.     { "timeout",    doppp_timeout,    0,    0,    NULLCHAR },
  155.     { "try",        doppp_try,    0,    0,    NULLCHAR },
  156.     { NULLCHAR },
  157. };
  158.  
  159. /* "ppp <iface> lcp [local | remote]" subcommands */
  160. static struct cmds Lcpside_cmds[] = {
  161.     { "accm",        dolcp_accm,    0,    0,    NULLCHAR },
  162.     { "acfc",        dolcp_acfc,    0,    0,    NULLCHAR },
  163.     { "authenticate",    dolcp_auth,    0,    0,    NULLCHAR },
  164.     { "magic",    dolcp_magic,    0,    0,    NULLCHAR },
  165.     { "mru",        dolcp_mru,    0,    0,    NULLCHAR },
  166.     { "pfc",        dolcp_pfc,    0,    0,    NULLCHAR },
  167.     { "default",    dolcp_default,    0,    0,    NULLCHAR },
  168.     { NULLCHAR },
  169. };
  170.  
  171.  
  172. int
  173. doppp_lcp(argc,argv,p)
  174. int argc;
  175. char *argv[];
  176. void *p;
  177. {
  178.     register struct iface *ifp = p;
  179.     register struct ppp_s *ppp_p = ifp->edv;
  180.  
  181.     return subcmd(Lcpcmds, argc, argv, &(ppp_p->fsm[Lcp]));
  182. }
  183.  
  184.  
  185. static int
  186. dolcp_local(argc,argv,p)
  187. int argc;
  188. char *argv[];
  189. void *p;
  190. {
  191.     struct fsm_s *fsm_p = p;
  192.     struct lcp_s *lcp_p = fsm_p->pdv;
  193.     return subcmd(Lcpside_cmds, argc, argv, &(lcp_p->local));
  194. }
  195.  
  196.  
  197. #if    0
  198. static
  199. #endif
  200. int
  201. dolcp_open(argc,argv,p)
  202. int argc;
  203. char *argv[];
  204. void *p;
  205. {
  206.     struct fsm_s *fsm_p = p;
  207.  
  208.     doppp_active( argc, argv, p );
  209.  
  210.     if ( fsm_p->ppp_p->phase >= pppLCP ) {
  211.         fsm_start( fsm_p );
  212.     }
  213.     return 0;
  214. }
  215.  
  216.  
  217. static int
  218. dolcp_remote(argc,argv,p)
  219. int argc;
  220. char *argv[];
  221. void *p;
  222. {
  223.     struct fsm_s *fsm_p = p;
  224.     struct lcp_s *lcp_p = fsm_p->pdv;
  225.     return subcmd(Lcpside_cmds, argc, argv, &(lcp_p->remote));
  226. }
  227.  
  228. /************************************************************************/
  229.  
  230. static int
  231. dolcp_accm(argc,argv,p)
  232. int argc;
  233. char *argv[];
  234. void *p;
  235. {
  236.     struct lcp_side_s *side_p = p;
  237.  
  238.     if (argc < 2) {
  239.         tprintf("0x%08lx\n",side_p->want.accm);
  240.     } else if (stricmp(argv[1],"allow") == 0) {
  241.         return bit16cmd(&(side_p->will_negotiate),LCP_N_ACCM,
  242.             "Allow ACCM", --argc, &argv[1] );
  243.     } else {
  244.         side_p->want.accm = strtoul(argv[1], NULLCHARP, 0);
  245.         if ( side_p->want.accm != LCP_ACCM_DEFAULT )
  246.             side_p->want.negotiate |= LCP_N_ACCM;
  247.         else
  248.             side_p->want.negotiate &= ~LCP_N_ACCM;
  249.     }
  250.     return 0;
  251. }
  252.  
  253.  
  254. static int
  255. dolcp_acfc(argc,argv,p)
  256. int argc;
  257. char *argv[];
  258. void *p;
  259. {
  260.     struct lcp_side_s *side_p = p;
  261.  
  262.     if (stricmp(argv[1],"allow") == 0) {
  263.         return bit16cmd(&(side_p->will_negotiate),LCP_N_ACFC,
  264.             "Allow Address/Control Field Compression", --argc, &argv[1] );
  265.     }
  266.     return bit16cmd( &(side_p->want.negotiate), LCP_N_ACFC,
  267.         "Address/Control Field Compression", argc, argv );
  268. }
  269.  
  270.  
  271. static int
  272. dolcp_auth(argc,argv,p)
  273. int argc;
  274. char *argv[];
  275. void *p;
  276. {
  277.     struct lcp_side_s *side_p = p;
  278.  
  279.     if (argc < 2) {
  280.         if ( side_p->want.negotiate & LCP_N_AUTHENT ) {
  281.             switch ( side_p->want.authentication ) {
  282.             case PPP_PAP_PROTOCOL:
  283.                 tprintf("Pap\n");
  284.                 break;
  285.             default:
  286.                 tprintf("0x%04x\n", side_p->want.authentication);
  287.                 break;
  288.             };
  289.         } else {
  290.             tprintf("None\n");
  291.         }
  292.     } else if (stricmp(argv[1],"allow") == 0) {
  293.         return bit16cmd(&(side_p->will_negotiate),LCP_N_AUTHENT,
  294.             "Allow Authentication", --argc, &argv[1] );
  295.     } else if (stricmp(argv[1],"pap") == 0) {
  296.         side_p->want.negotiate |= LCP_N_AUTHENT;
  297.         side_p->want.authentication = PPP_PAP_PROTOCOL;
  298.     } else if (stricmp(argv[1],"none") == 0) {
  299.         side_p->want.negotiate &= ~LCP_N_AUTHENT;
  300.     } else {
  301.         tprintf("allow pap none\n");
  302.         return 1;
  303.     }
  304.     return 0;
  305. }
  306.  
  307.  
  308. static int
  309. dolcp_magic(argc,argv,p)
  310. int argc;
  311. char *argv[];
  312. void *p;
  313. {
  314.     struct lcp_side_s *side_p = p;
  315.     int result = 0;
  316.  
  317.     if (argc < 2) {
  318.         tprintf("%d\n",side_p->want.magic_number);
  319.     } else if (stricmp(argv[1],"allow") == 0) {
  320.         return bit16cmd(&(side_p->will_negotiate),LCP_N_MAGIC,
  321.             "Allow Magic Number", --argc, &argv[1] );
  322.     } else {
  323.         register int32 x = strtoul(argv[1], NULLCHARP, 0);
  324.  
  325.         if ( !x ) {
  326.             int test;
  327.  
  328.             /* Check for keyword */
  329.             result = setbool( &test, "Magic Number", argc, argv );
  330.  
  331.             if ( test ) {
  332.                 /* Make a non-zero random number */
  333.                 x = Clock << ((Clock & 0xf)+8);
  334.             }
  335.         }
  336.         if ( x ) {
  337.             side_p->want.negotiate |= LCP_N_MAGIC;
  338.         } else {
  339.             side_p->want.negotiate &= ~LCP_N_MAGIC;
  340.         }
  341.         side_p->want.magic_number = x;
  342.     }
  343.     return result;
  344. }
  345.  
  346.  
  347. static int
  348. dolcp_mru(argc,argv,p)
  349. int argc;
  350. char *argv[];
  351. void *p;
  352. {
  353.     struct lcp_side_s *side_p = p;
  354.  
  355.     if (argc < 2) {
  356.         tprintf("%d\n",side_p->want.mru);
  357.     } else if (stricmp(argv[1],"allow") == 0) {
  358.         return bit16cmd(&(side_p->will_negotiate),LCP_N_MRU,
  359.             "Allow MRU", --argc, &argv[1] );
  360.     } else {
  361.         register int x = (int)strtol( argv[1], NULLCHARP, 0 );
  362.  
  363.         if (x < LCP_MRU_LO || x > LCP_MRU_HI) {
  364.             tprintf("MRU %s (%d) out of range %d thru %d\n",
  365.                 argv[1], x, LCP_MRU_LO, LCP_MRU_HI);
  366.             return -1;
  367.         } else if ( x != LCP_MRU_DEFAULT ) {
  368.             side_p->want.negotiate |= LCP_N_MRU;
  369.         } else {
  370.             side_p->want.negotiate &= ~LCP_N_MRU;
  371.         }
  372.         side_p->want.mru = x;
  373.     }
  374.     return 0;
  375. }
  376.  
  377.  
  378. static int
  379. dolcp_pfc(argc,argv,p)
  380. int argc;
  381. char *argv[];
  382. void *p;
  383. {
  384.     struct lcp_side_s *side_p = p;
  385.  
  386.     if (stricmp(argv[1],"allow") == 0) {
  387.         return bit16cmd(&(side_p->will_negotiate),LCP_N_PFC,
  388.             "Allow Protocol Field Compression", --argc, &argv[1] );
  389.     }
  390.     return bit16cmd( &(side_p->want.negotiate), LCP_N_PFC,
  391.         "Protocol Field Compression", argc, argv );
  392. }
  393.  
  394.  
  395. static int
  396. dolcp_default(argc,argv,p)
  397. int argc;
  398. char *argv[];
  399. void *p;
  400. {
  401.     struct lcp_side_s *side_p = p;
  402.  
  403.     ASSIGN( side_p->want, lcp_default );
  404.     return 0;
  405. }
  406.  
  407.  
  408. /************************************************************************/
  409. /*            E V E N T   P R O C E S S I N G            */
  410. /************************************************************************/
  411.  
  412. static void lcp_option(
  413.     struct mbuf **bpp,
  414.     struct lcp_value_s *value_p,
  415.     byte_t o_type,
  416.     byte_t o_length,
  417.     struct mbuf **copy_bpp )
  418. {
  419.     struct mbuf *bp;
  420.     register char *cp;
  421.     register int toss = o_length - OPTION_HDR_LEN;
  422.  
  423.     if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
  424.         return;
  425.     }
  426.     cp = bp->data;
  427.     *cp++ = o_type;
  428.     *cp++ = o_length;
  429.  
  430.     switch ( o_type ) {
  431.     case LCP_MRU:
  432.         put16(cp, value_p->mru);
  433.         toss -= 2;
  434. #ifdef PPP_DEBUG_OPTIONS
  435. if (PPPtrace & PPP_DEBUG_OPTIONS)
  436.     trace_log(PPPiface, "    making MRU: %d", value_p->mru);
  437. #endif
  438.         break;
  439.  
  440.     case LCP_ACCM:
  441.         put32(cp, value_p->accm);
  442.         toss -= 4;
  443. #ifdef PPP_DEBUG_OPTIONS
  444. if (PPPtrace & PPP_DEBUG_OPTIONS)
  445.     trace_log(PPPiface, "    making ACCM: 0x%08lx", value_p->accm);
  446. #endif
  447.         break;
  448.  
  449.     case LCP_AUTHENT:
  450.         put16(cp, value_p->authentication);
  451.         toss -= 2;
  452. #ifdef PPP_DEBUG_OPTIONS
  453. if (PPPtrace & PPP_DEBUG_OPTIONS)
  454.     trace_log(PPPiface, "    making Auth Protocol: 0x%04x",
  455.         value_p->authentication);
  456. #endif
  457.         break;
  458.  
  459.     case LCP_MAGIC:
  460.         put32(cp, value_p->magic_number);
  461.         toss -= 4;
  462. #ifdef PPP_DEBUG_OPTIONS
  463. if (PPPtrace & PPP_DEBUG_OPTIONS)
  464.     trace_log(PPPiface, "    making Magic Number: 0x%08lx",
  465.         value_p->magic_number);
  466. #endif
  467.         break;
  468.  
  469.     case LCP_PFC:
  470. #ifdef PPP_DEBUG_OPTIONS
  471. if (PPPtrace & PPP_DEBUG_OPTIONS)
  472.     trace_log(PPPiface, "    making Protocol compression");
  473. #endif
  474.         break;
  475.  
  476.     case LCP_ACFC:
  477. #ifdef PPP_DEBUG_OPTIONS
  478. if (PPPtrace & PPP_DEBUG_OPTIONS)
  479.     trace_log(PPPiface, "    making Addr/Ctl compression");
  480. #endif
  481.         break;
  482.  
  483.     case LCP_ENCRYPT:        /* not implemented */
  484.     case LCP_QUALITY:        /* not implemented */
  485.     default:
  486. #ifdef PPP_DEBUG_OPTIONS
  487. if (PPPtrace & PPP_DEBUG_OPTIONS)
  488.     trace_log(PPPiface, "    making unimplemented type %d", o_type);
  489. #endif
  490.         break;
  491.     };
  492.  
  493.     while ( toss-- > 0 ) {
  494.         *cp++ = pullchar(copy_bpp);
  495.     }
  496.     bp->cnt += o_length;
  497.     append(bpp, bp);
  498. }
  499.  
  500.  
  501. /************************************************************************/
  502. /* Build a list of options */
  503.  
  504. static void lcp_makeoptions(
  505.     struct mbuf **bpp,
  506.     struct lcp_value_s *value_p,
  507.     int16 negotiating )
  508. {
  509.     register int o_type;
  510.  
  511.     PPP_DEBUG_ROUTINES("lcp_makeoptions()");
  512.  
  513.     for ( o_type = 1; o_type <= LCP_OPTION_LIMIT; o_type++ ) {
  514.         if (negotiating & (1 << o_type)) {
  515.             lcp_option( bpp, value_p,
  516.                 o_type, option_length[ o_type ], NULLBUFP);
  517.         }
  518.     }
  519. }
  520.  
  521.  
  522. /************************************************************************/
  523. /* Build a request to send to remote host */
  524. static struct mbuf *
  525. lcp_makereq(fsm_p)
  526. struct fsm_s *fsm_p;
  527. {
  528.     struct lcp_s *lcp_p = fsm_p->pdv;
  529.     struct mbuf *req_bp = NULLBUF;
  530.  
  531.     PPP_DEBUG_ROUTINES("lcp_makereq()");
  532.  
  533.     lcp_makeoptions( &req_bp, &(lcp_p->local.work),
  534.                 lcp_p->local.work.negotiate );
  535.     return(req_bp);
  536. }
  537.  
  538.  
  539. /************************************************************************/
  540. /* Check the options, updating the working values.
  541.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  542.  */
  543. static int
  544. lcp_check( bpp, lcp_p, side_p, option_p, request )
  545. struct mbuf **bpp;
  546. struct lcp_s *lcp_p;
  547. struct lcp_side_s *side_p;
  548. struct option_hdr *option_p;
  549. int request;
  550. {
  551.     int toss = option_p->len - OPTION_HDR_LEN;
  552.     int option_result = CONFIG_ACK;        /* Assume good values */
  553.  
  554.     switch(option_p->type) {
  555.     case LCP_MRU:
  556.         side_p->work.mru = pull16(bpp);
  557.         toss -= 2;
  558. #ifdef PPP_DEBUG_OPTIONS
  559. if (PPPtrace & PPP_DEBUG_OPTIONS)
  560.     trace_log(PPPiface, "    checking MRU: %d", side_p->work.mru);
  561. #endif
  562.         /* Check if new value is appropriate */
  563.         if (side_p->work.mru < LCP_MRU_LO) {
  564.             side_p->work.mru = LCP_MRU_LO;
  565.             option_result = CONFIG_NAK;
  566.         } else if (side_p->work.mru > LCP_MRU_HI) {
  567.             side_p->work.mru = LCP_MRU_HI;
  568.             option_result = CONFIG_NAK;
  569.         }
  570.         if ( request && (side_p->want.negotiate & LCP_N_MRU)
  571.           && side_p->work.mru > side_p->want.mru ) {
  572.             side_p->work.mru = side_p->want.mru;
  573.             option_result = side_p->want.mru;
  574.         }
  575.         break;
  576.  
  577.     case LCP_ACCM:
  578.         side_p->work.accm = pull32(bpp);
  579.         toss -= 4;
  580. #ifdef PPP_DEBUG_OPTIONS
  581. if (PPPtrace & PPP_DEBUG_OPTIONS)
  582.     trace_log(PPPiface, "    checking ACCM: 0x%08lx", side_p->work.accm);
  583. #endif
  584.         /* Remote host may ask to escape more control  */
  585.         /* characters than we require, but must escape */
  586.         /* at least the control chars that we require. */
  587.         if ( (!request || (side_p->want.negotiate & LCP_N_ACCM))
  588.           && side_p->work.accm !=
  589.                (side_p->work.accm | side_p->want.accm) ) {
  590.             side_p->work.accm |= side_p->want.accm;
  591.             option_result = CONFIG_NAK;
  592.         }
  593.         break;
  594.  
  595.     case LCP_AUTHENT:
  596.         side_p->work.authentication = pull16(bpp);
  597.         toss -= 2;
  598. #ifdef PPP_DEBUG_OPTIONS
  599. if (PPPtrace & PPP_DEBUG_OPTIONS)
  600.     trace_log(PPPiface, "    checking Auth Protocol: 0x%04x",
  601.         side_p->work.authentication);
  602. #endif
  603.         /* Check if new value is appropriate */
  604.         switch ( side_p->work.authentication ) {
  605.         case PPP_PAP_PROTOCOL:
  606.             /* Yes */
  607.             break;
  608.         default:
  609.             side_p->work.authentication = PPP_PAP_PROTOCOL;
  610.             option_result = CONFIG_NAK;
  611.             break;
  612.         };
  613.         break;
  614.  
  615.     case LCP_MAGIC:
  616.         side_p->work.magic_number = pull32(bpp);
  617.         toss -= 4;
  618. #ifdef PPP_DEBUG_OPTIONS
  619. if (PPPtrace & PPP_DEBUG_OPTIONS)
  620.     trace_log(PPPiface, "    checking Magic Number: 0x%08lx",
  621.         side_p->work.magic_number);
  622. #endif
  623.  
  624.         /* Ensure that magic numbers are different */
  625.         if (side_p->work.magic_number == 0L
  626.          || lcp_p->remote.work.magic_number == lcp_p->local.work.magic_number) {
  627.             side_p->work.magic_number += Clock;
  628.             option_result = CONFIG_NAK;
  629.         }
  630.         break;
  631.  
  632.     case LCP_PFC:
  633. #ifdef PPP_DEBUG_OPTIONS
  634. if (PPPtrace & PPP_DEBUG_OPTIONS)
  635.     trace_log(PPPiface, "    checking Protocol compression");
  636. #endif
  637.         break;
  638.  
  639.     case LCP_ACFC:
  640. #ifdef PPP_DEBUG_OPTIONS
  641. if (PPPtrace & PPP_DEBUG_OPTIONS)
  642.     trace_log(PPPiface, "    checking Addr/Ctl compression");
  643. #endif
  644.         break;
  645.  
  646.     case LCP_ENCRYPT:        /* not implemented */
  647.     case LCP_QUALITY:        /* not implemented */
  648.     default:
  649.         option_result = CONFIG_REJ;
  650.         break;
  651.     };
  652.  
  653.     if (option_p->type > LCP_OPTION_LIMIT
  654.      || !(side_p->will_negotiate & (1 << option_p->type))) {
  655.         option_result = CONFIG_REJ;
  656.     }
  657.  
  658.     if ( toss < 0 )
  659.         return -1;
  660.  
  661.     if ( !request  &&  toss > 0 ) {
  662.         /* toss extra bytes in option */
  663.         while( toss-- > 0 ) {
  664.             if ( pullchar(bpp) == -1 )
  665.                 return -1;
  666.         }
  667.     }
  668.  
  669.     return (option_result);
  670. }
  671.  
  672.  
  673. /************************************************************************/
  674. /* Check Link Control options requested by the remote host */
  675. static int
  676. lcp_request(fsm_p, config, data)
  677. struct fsm_s *fsm_p;
  678. struct config_hdr *config;
  679. struct mbuf *data;
  680. {
  681.     struct lcp_s *lcp_p = fsm_p->pdv;
  682.     int32 signed_length = config->len;
  683.     struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  684.     int reply_result = CONFIG_ACK;        /* reply to request */
  685.     int16 desired;                /* desired to negotiate */
  686.     struct option_hdr option;        /* option header storage */
  687.     int option_result;            /* option reply */
  688.  
  689.     PPP_DEBUG_ROUTINES("lcp_request()");
  690.     lcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  691.  
  692.     /* Process options requested by remote host */
  693.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  694.         if ((signed_length -= option.len) < 0) {
  695.             PPP_DEBUG_CHECKS("LCP REQ: bad header length");
  696.             free_p(data);
  697.             free_p(reply_bp);
  698.             return -1;
  699.         }
  700.  
  701.         if ( ( option_result = lcp_check( &data, lcp_p,
  702.                 &(lcp_p->remote), &option, TRUE ) ) == -1 ) {
  703.             PPP_DEBUG_CHECKS("LCP REQ: ran out of data");
  704.             free_p(data);
  705.             free_p(reply_bp);
  706.             return -1;
  707.         }
  708.  
  709. #ifdef PPP_DEBUG_OPTIONS
  710. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  711.     trace_log(PPPiface, "LCP REQ: result %s, option %d, length %d",
  712.         fsmCodes[option_result],
  713.         option.type,
  714.         option.len);
  715. }
  716. #endif
  717.         if ( option_result < reply_result ) {
  718.             continue;
  719.         } else if ( option_result > reply_result ) {
  720.             /* Discard current list of replies */
  721.             free_p(reply_bp);
  722.             reply_bp = NULLBUF;
  723.             reply_result = option_result;
  724.         }
  725.  
  726.         /* remember that we processed option */
  727.         if ( option_result != CONFIG_REJ
  728.           && option.type <= LCP_OPTION_LIMIT ) {
  729.             lcp_p->remote.work.negotiate |= (1 << option.type);
  730.         }
  731.  
  732.         /* Add option response to the return list */
  733.         lcp_option( &reply_bp, &(lcp_p->remote.work),
  734.             option.type, option.len, &data );
  735.     }
  736.  
  737.     /* Now check for any missing options which are desired */
  738.     if ( fsm_p->retry_nak > 0
  739.      &&  (desired = lcp_p->remote.want.negotiate
  740.                & ~lcp_p->remote.work.negotiate) != 0 ) {
  741.         switch ( reply_result ) {
  742.         case CONFIG_ACK:
  743.             free_p(reply_bp);
  744.             reply_bp = NULLBUF;
  745.             reply_result = CONFIG_NAK;
  746.             /* fallthru */
  747.         case CONFIG_NAK:
  748.             lcp_makeoptions( &reply_bp, &(lcp_p->remote.want),
  749.                 desired );
  750.             fsm_p->retry_nak--;
  751.             break;
  752.         case CONFIG_REJ:
  753.             /* do nothing */
  754.             break;
  755.         };
  756.     } else if ( reply_result == CONFIG_NAK ) {
  757.         /* if too many NAKs, reject instead */
  758.         if ( fsm_p->retry_nak > 0 )
  759.             fsm_p->retry_nak--;
  760.         else
  761.             reply_result = CONFIG_REJ;
  762.     }
  763.  
  764.     /* Send ACK/NAK/REJ to remote host */
  765.     fsm_send(fsm_p, reply_result, config->id, reply_bp);
  766.     free_p(data);
  767.     return (reply_result != CONFIG_ACK);
  768. }
  769.  
  770.  
  771. /************************************************************************/
  772. /* Process configuration ACK sent by remote host */
  773. static int
  774. lcp_ack(fsm_p, config, data)
  775. struct fsm_s *fsm_p;
  776. struct config_hdr *config;
  777. struct mbuf *data;
  778. {
  779.     struct mbuf *req_bp;
  780.     int error = FALSE;
  781.  
  782.     PPP_DEBUG_ROUTINES("lcp_ack()");
  783.  
  784.     /* ID field must match last request we sent */
  785.     if (config->id != fsm_p->lastid) {
  786.         PPP_DEBUG_CHECKS("LCP ACK: wrong ID");
  787.         free_p(data);
  788.         return -1;
  789.     }
  790.  
  791.     /* Get a copy of last request we sent */
  792.     req_bp = lcp_makereq(fsm_p);
  793.  
  794.     /* Overall buffer length should match */
  795.     if (config->len != len_p(req_bp)) {
  796.         PPP_DEBUG_CHECKS("LCP ACK: buffer length mismatch");
  797.         error = TRUE;
  798.     } else {
  799.         register int req_char;
  800.         register int ack_char;
  801.  
  802.         /* Each byte should match */
  803.         while ((req_char = pullchar(&req_bp)) != -1) {
  804.             if ((ack_char = pullchar(&data)) == -1
  805.              || ack_char != req_char ) {
  806.                 PPP_DEBUG_CHECKS("LCP ACK: data mismatch");
  807.                 /*trace_log(PPPiface, "req=%02X, ack=%02X", req_char, ack_char);*/
  808.                 error = TRUE;
  809.                 break;
  810.             }
  811.         }
  812.     }
  813.     free_p(req_bp);
  814.     free_p(data);
  815.  
  816.     if (error) {
  817.         return -1;
  818.     }
  819.  
  820.     PPP_DEBUG_CHECKS("LCP ACK: valid");
  821.     return 0;
  822. }
  823.  
  824.  
  825. /************************************************************************/
  826. /* Process configuration NAK sent by remote host */
  827. static int
  828. lcp_nak(fsm_p, config, data)
  829. struct fsm_s *fsm_p;
  830. struct config_hdr *config;
  831. struct mbuf *data;
  832. {
  833.     struct lcp_s *lcp_p = fsm_p->pdv;
  834.     struct lcp_side_s *local_p = &(lcp_p->local);
  835.     int32 signed_length = config->len;
  836.     struct option_hdr option;
  837.     int last_option = 0;
  838.     int result;
  839.  
  840.     PPP_DEBUG_ROUTINES("lcp_nak()");
  841.  
  842.     /* ID field must match last request we sent */
  843.     if (config->id != fsm_p->lastid) {
  844.         PPP_DEBUG_CHECKS("LCP NAK: wrong ID");
  845.         free_p(data);
  846.         return -1;
  847.     }
  848.  
  849.     /* First, process in order.  Then, process extra "important" options */
  850.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  851.         if ((signed_length -= option.len) < 0) {
  852.             PPP_DEBUG_CHECKS("LCP NAK: bad header length");
  853.             free_p(data);
  854.             return -1;
  855.         }
  856.         if ( option.type > LCP_OPTION_LIMIT ) {
  857.             PPP_DEBUG_CHECKS("LCP NAK: option out of range");
  858.         } else if ( option.type < last_option
  859.           || !(local_p->work.negotiate & (1 << option.type)) ) {
  860.             if (local_p->work.negotiate & (1 << option.type)) {
  861.                 PPP_DEBUG_CHECKS("LCP NAK: option out of order");
  862.                 free_p(data);
  863.                 return -1;        /* was requested */
  864.             }
  865.             local_p->work.negotiate |= (1 << option.type);
  866.             last_option = LCP_OPTION_LIMIT + 1;
  867.         } else {
  868.             last_option = option.type;
  869.         }
  870.         if ( ( result = lcp_check( &data, lcp_p,
  871.                 local_p, &option, FALSE ) ) == -1 ) {
  872.             PPP_DEBUG_CHECKS("LCP NAK: ran out of data");
  873.             free_p(data);
  874.             return -1;
  875.         }
  876.         /* update the negotiation status */
  877.         if ( result == CONFIG_REJ
  878.           && option.type <= LCP_OPTION_LIMIT ) {
  879.             local_p->work.negotiate &= ~(1 << option.type);
  880.         }
  881.     }
  882.     PPP_DEBUG_CHECKS("LCP NAK: valid");
  883.     free_p(data);
  884.     return 0;
  885. }
  886.  
  887.  
  888. /************************************************************************/
  889. /* Process configuration reject sent by remote host */
  890. static int
  891. lcp_reject(fsm_p, config, data)
  892. struct fsm_s *fsm_p;
  893. struct config_hdr *config;
  894. struct mbuf *data;
  895. {
  896.     struct lcp_s *lcp_p = fsm_p->pdv;
  897.     struct lcp_side_s *local_p = &(lcp_p->local);
  898.     int32 signed_length = config->len;
  899.     struct option_hdr option;
  900.     int last_option = 0;
  901.  
  902.     PPP_DEBUG_ROUTINES("lcp_reject()");
  903.  
  904.     /* ID field must match last request we sent */
  905.     if (config->id != fsm_p->lastid) {
  906.         PPP_DEBUG_CHECKS("LCP REJ: wrong ID");
  907.         free_p(data);
  908.         return -1;
  909.     }
  910.  
  911.     /* Process in order, checking for errors */
  912.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  913.         register int k;
  914.  
  915.         if ((signed_length -= option.len) < 0) {
  916.             PPP_DEBUG_CHECKS("LCP REJ: bad header length");
  917.             free_p(data);
  918.             return -1;
  919.         }
  920.         if ( option.type > LCP_OPTION_LIMIT ) {
  921.             PPP_DEBUG_CHECKS("LCP REJ: option out of range");
  922.         } else if ( option.type < last_option
  923.          || !(local_p->work.negotiate & (1 << option.type))) {
  924.             PPP_DEBUG_CHECKS("LCP REJ: option out of order");
  925.             free_p(data);
  926.             return -1;
  927.         }
  928.         for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  929.             if ( pullchar(&data) == -1 ) {
  930.                 PPP_DEBUG_CHECKS("LCP REJ: ran out of data");
  931.                 free_p(data);
  932.                 return -1;
  933.             }
  934.         }
  935.         last_option = option.type;
  936.  
  937.         if ( option.type <= LCP_OPTION_LIMIT ) {
  938.             local_p->work.negotiate &= ~(1 << option.type);
  939.         }
  940.     }
  941.     PPP_DEBUG_CHECKS("LCP REJ: valid");
  942.     free_p(data);
  943.     return 0;
  944. }
  945.  
  946.  
  947. /************************************************************************/
  948. /*            I N I T I A L I Z A T I O N            */
  949. /************************************************************************/
  950.  
  951. /* Check for PPP Network-Layer Protocol Phase */
  952. void
  953. ppp_ready(ppp_p)
  954. struct ppp_s *ppp_p;
  955. {
  956.     if ( !(ppp_p->flags & (PPP_AP_LOCAL | PPP_AP_REMOTE)) ) {
  957.         /* no pending authentication */
  958.         ppp_p->phase = pppREADY;
  959.  
  960.         ppp_p->upsince = secclock();
  961.         fsm_start( &(ppp_p->fsm[IPcp]) );
  962.     }
  963. }
  964.  
  965.  
  966. /****************************************************************************/
  967. /* Reset configuration options before request */
  968. static void
  969. lcp_reset(fsm_p)
  970. struct fsm_s *fsm_p;
  971. {
  972.     struct lcp_s *lcp_p =     fsm_p->pdv;
  973.  
  974.     PPP_DEBUG_ROUTINES("lcp_reset()");
  975.  
  976.     if ( lcp_p->local.want.negotiate & LCP_N_MAGIC ) {
  977.         lcp_p->local.want.magic_number += Clock;
  978.     }
  979.  
  980.     ASSIGN( lcp_p->local.work, lcp_p->local.want );
  981.     lcp_p->local.will_negotiate |= lcp_p->local.want.negotiate;
  982.  
  983.     lcp_p->remote.work.negotiate = FALSE;
  984.     lcp_p->remote.will_negotiate |= lcp_p->remote.want.negotiate;
  985. }
  986.  
  987.  
  988. /************************************************************************/
  989. /* Prepare to begin configuration exchange */
  990. static void
  991. lcp_starting(fsm_p)
  992. struct fsm_s *fsm_p;
  993. {
  994.     PPP_DEBUG_ROUTINES("lcp_starting()");
  995.  
  996.     fsm_p->ppp_p->phase = pppLCP;
  997. }
  998.  
  999.  
  1000. /************************************************************************/
  1001. /* After termination */
  1002. static void
  1003. lcp_stopping(fsm_p)
  1004. struct fsm_s *fsm_p;
  1005. {
  1006. #if    0
  1007.     struct iface *ifp = fsm_p->ppp_p->iface;
  1008. #endif
  1009.  
  1010.     PPP_DEBUG_ROUTINES("lcp_stopping()");
  1011.  
  1012. #if    0
  1013.     /* Tell the dialer to shut down */
  1014.     if ( ifp->supv != NULLPROC )
  1015.         alert( ifp->supv, EABORT );
  1016.  
  1017.     /* Now, tell the device to go down.
  1018.      * In turn, it should tell our IO status
  1019.      * when it has gone down.
  1020.      */
  1021.  
  1022.     ifp->ioctl(ifp,PARAM_DOWN,TRUE,0L);
  1023. #endif
  1024.  
  1025. }
  1026.  
  1027.  
  1028. /************************************************************************/
  1029. /* Close higher levels in preparation for link shutdown */
  1030. static void
  1031. lcp_closing(fsm_p)
  1032. struct fsm_s *fsm_p;
  1033. {
  1034.     struct ppp_s *ppp_p = fsm_p->ppp_p;
  1035.  
  1036.     ppp_p->phase = pppTERMINATE;
  1037.  
  1038.     fsm_down( &(ppp_p->fsm[IPcp]) );
  1039.     pap_down( &(ppp_p->fsm[Pap]) );
  1040. }
  1041.  
  1042.  
  1043. #ifdef TURBOC_SWITCH_BUG
  1044. #pragma option -G-
  1045. #endif
  1046.  
  1047. /************************************************************************/
  1048. /* configuration negotiation complete */
  1049. static void
  1050. lcp_opening(fsm_p)
  1051. struct fsm_s *fsm_p;
  1052. {
  1053.     struct lcp_s *lcp_p =     fsm_p->pdv;
  1054.     struct iface *ifp =     fsm_p->ppp_p->iface;
  1055.  
  1056.     if (ifp->mtu != lcp_p->remote.work.mru) {
  1057.         /* Set new Max Transmission Unit for outgoing packets */
  1058.         ifp->mtu = lcp_p->remote.work.mru;
  1059.         if (PPPtrace > 1)
  1060.             trace_log(PPPiface,"    Set new MTU for outgoing packets: %d",
  1061.                 ifp->mtu);
  1062.     }
  1063.  
  1064.     /* check for authentication */
  1065.     fsm_p->ppp_p->phase = pppAP;
  1066.     fsm_p->ppp_p->flags &= ~(PPP_AP_LOCAL | PPP_AP_REMOTE);
  1067.     free(fsm_p->ppp_p->peername);
  1068.     fsm_p->ppp_p->peername = NULLCHAR;
  1069.  
  1070.     if (lcp_p->local.work.negotiate & LCP_N_AUTHENT) {
  1071.         switch (lcp_p->local.work.authentication) {
  1072.         case PPP_PAP_PROTOCOL:
  1073.             pap_local(fsm_p->ppp_p);
  1074.             break;
  1075.         };
  1076.     }
  1077.     if (lcp_p->remote.work.negotiate & LCP_N_AUTHENT) {
  1078.         switch (lcp_p->remote.work.authentication) {
  1079.         case PPP_PAP_PROTOCOL:
  1080.             pap_remote(fsm_p->ppp_p);
  1081.             break;
  1082.         };
  1083.     }
  1084.  
  1085.     /* re-check for authentication */
  1086.     ppp_ready(fsm_p->ppp_p);
  1087. }
  1088.  
  1089. #ifdef TURBOC_SWITCH_BUG
  1090. #pragma option -G
  1091. #endif
  1092.  
  1093.  
  1094. /************************************************************************/
  1095. static void
  1096. lcp_free(fsm_p)
  1097. struct fsm_s *fsm_p;
  1098. {
  1099.     /* nothing to do */
  1100. }
  1101.  
  1102.  
  1103. /* Initialize configuration structure */
  1104. void
  1105. lcp_init(ppp_p)
  1106. struct ppp_s *ppp_p;
  1107. {
  1108.     struct fsm_s *fsm_p = &(ppp_p->fsm[Lcp]);
  1109.     struct lcp_s *lcp_p;
  1110.  
  1111.     PPPtrace = ppp_p->trace;
  1112.     PPPiface = ppp_p->iface;
  1113.  
  1114.     PPP_DEBUG_ROUTINES("lcp_init()");
  1115.  
  1116.     fsm_p->ppp_p = ppp_p;
  1117.     fsm_p->pdc = &lcp_constants;
  1118.     fsm_p->pdv =
  1119.     lcp_p = callocw(1,sizeof(struct lcp_s));
  1120.  
  1121.     /* Set option parameters to first request defaults */
  1122.     ASSIGN( lcp_p->local.want, lcp_default );
  1123.     lcp_p->local.will_negotiate = lcp_negotiate;
  1124.  
  1125.     ASSIGN( lcp_p->remote.want, lcp_default );
  1126.     ASSIGN( lcp_p->remote.work, lcp_default );
  1127.     lcp_p->remote.will_negotiate = lcp_negotiate;
  1128.  
  1129.     fsm_init(fsm_p);
  1130. }
  1131.  
  1132.  
  1133.